#include "string.h"
#include "elf.h"
#include "kparam.h"
#include "proc.h"
#include "protect.h"
#include "ktty.h"

#include "debug.h"

PUBLIC char kstack[4 * 1024];
//EXTERN int switch_to(struct proc *pick_proc);


#if (KDEBUG == 1)

#define switch_to_user(proc_p)\
{\
	uint_32 cr3 = ((struct proc *)proc_p)->context.cr3;\
	cur_proc = proc_p;\
	__asm__("movl %0, %%eax;		\n\t"\
			"movl %%eax, %%cr3;		\n\t"\
			"addl $0x04, %%esp;	\n\t"\
			"pushfl;			\n\t"\
			"movl (%%esp), %%eax;	\n\t"\
			"movl $0x2B, 16(%%esp);	\n\t"\	
			"movl $0x7FFFF0, 12(%%esp);	\n\t"\
			"movl %%eax, 8(%%esp);	\n\t"\
			"movl $0x23, 4(%%esp);	\n\t"\
			"movl $0x400000, (%%esp)	\n\t"\
			"iret;	\n\t"\
			:\
			:"m"(cr3));\
}
/* since the file system is not implemented, now we are in debug mode, 
 * and just test the syscall module.
 * 
 */ 
int main(void){
	/* bring up the first process and move to user space */
	/* first process is loaded in the secode page block, */
	/* that is located in physical memory address (1M + 64 * 4K )*/
	struct proc *proc_p = proc_new();
	uint_32 phy;
	if (proc_p){
		proc_p->pid = PROC_IDLE;
		proc_p->priv = PRIV0;
		proc_p->ticks = DEFAULT_TICK;
		proc_p->sleep_ticks = 0;
		proc_p->status = READY;
		memcpy(proc_p->name,"idle",strlen("idle"));

		page_alloc(&phy);
		proc_p->mm.start_vm = 0x400000;
		proc_p->mm.start_phy = phy;
		page_map(&(proc_p->mm));
		
		memset((char *)(&(proc_p->context)),0x00,CONTEXT_LEN);
		proc_p->context.esp0 = K_STACK;
		proc_p->context.esp3 = U_STACK;
		proc_p->context.cr3 = phy;
		
		proc_p->msg = NULL;
		proc_p->child = NULL;
		proc_p->ipc_with = NULL;
		proc_p->next = NULL;
		proc_en_ready_queue(proc_p);

		switch_to_user(proc_p->context.cr3);
	}
	return 0;
}

#else
//#define switch_to_user 	switch_to

/* the interval between two server 
	processes is 4096 bytes 
*/
#define SV_NEXT		PG_SIZE		

/* 
	get the entrance of every server process 
	and transfer the data synchronously
*/
#define SV_PM		0
#define SV_TTY		1

struct serv_img{
	int sv_id;
	int sv_proc_id;
	int sv_size;
	char name[16];
};

struct serv_img sv_img[]={
		//{ SV_PM,	PROC_PM,	NULL,		"pm"},
		//{ SV_TTY,	PROC_TTY,	NULL,		"tty"},
		{ INVALID,	INVALID,	INVALID,	{NULL}}
};


static int server_page_init(struct task_context *context, int task_phy_start){
	return 0;
}

static int server_context_init(struct task_context *context, int task_phy_start){
#if 0
	context->eip = elf_entry((Elf32_Ehdr *)task_phy_start);
	context->eflags = INVALID;
	context->eax = 0;
	context->ecx = 0;
	context->edx = 0;
	context->ebx = 0;
	/* ***** */
	context->esp3 = PROC_USER_STACK; 
	context->ebp = 0;
	context->esi = 0;
	context->edi = 0;
	context->cs = USER_CODE_SEL;
	context->ds = USER_DATA_SEL;
	context->ss3 = USER_DATA_SEL;
	context->es = USER_DATA_SEL;
	context->gs = USER_DATA_SEL;
	context->fs = USER_DATA_SEL;
	/* ****** */
	context->esp0 =  PROC_KERN_STACK; 
	context->ss0 = KERNEL_CODE_SEL;

	context->cr3 = task_phy_start;
#endif
	return 0;
}

int server_init(void){
	int i;
	struct proc *proc_p = NULL;
	Elf32_Off sv_off;
	Addr sv_start = round_forward(K_BASE,SV_NEXT);

	for (i = 0; sv_img[i].sv_id != INVALID; i++){
		while(!is_elf((Elf32_Ehdr*) sv_start)){
			sv_start = round_forward(sv_start,SV_NEXT);
		}
		
		sv_off = elf_read((Elf32_Ehdr*)sv_start);

		/* bring up server processes */
		proc_p = &proc[sv_img[i].sv_proc_id];
		proc_p->pid = sv_img[i].sv_id;
		proc_p->priv = PRIV0;
		proc_p->ticks = DEFAULT_TICK;
		proc_p->status = READY;
		
		strcpy(proc_p->name,sv_img[i].name);

		/* process page init */
		server_page_init(&(proc_p->context),sv_start);

		/* context init */
		server_context_init(&(proc_p->context),sv_start);

		proc_p->msg = NULL;
		proc_p->child = NULL;

#if 0
		proc_p->brother = NULL;
		proc_p->father= NULL;
#endif
		proc_p->next = NULL;
	}
	return 0;
}

int main(void){
	uint_32 phy_size;

	
	page_info_init(phy_size);
	
	//kprintf("initializing kmap for user process...\n");
	//kmap_init();
	
	//kprintf("initializing servers...\n");
	//server_init();

	//kprintf("to user mode and processes rolling start.\n");
	//switch_to_user(&proc[PROC_IDLE]);
	//do_fork(NULL);
	//sched(NULL);

	for (;;){
	}
	return 0;
}
#endif
/* EOF */

